package org.domeos.framework.api.task;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.annotation.PostConstruct;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.domeos.framework.api.biz.productline.ProductLineBiz;
import org.domeos.framework.api.model.productline.ProductLine;
import org.domeos.framework.api.model.productline.ProductLineTree;
import org.domeos.framework.engine.RedisUtil;
import org.domeos.framework.engine.exception.DaoException;
import org.domeos.global.GlobalConstant;
import org.domeos.util.HttpClientUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 产品线树形结构
 * 
 * @author haqiaolong
 *
 */
@Component
public class ProductLineUpdater {

	private static AtomicBoolean started = new AtomicBoolean(false);

	private static Logger logger = LoggerFactory
			.getLogger(ProductLineUpdater.class);

	private ScheduledExecutorService scheduledExecutor = Executors
			.newScheduledThreadPool(1);

	private ObjectMapper mapper = new ObjectMapper();
	
	@Autowired
	ProductLineBiz productLineBiz;

	@Value("${cmdb.tree.api}")
	private String cmdbApi;

	@PostConstruct
	public void init() {
		if (started.compareAndSet(false, true)) {
			logger.info("init {}, start scheduled task checker.",
					ProductLineUpdater.class.toString());
			scheduledExecutor.scheduleWithFixedDelay(
					new UpdateProductLineTask(), 1, 10, TimeUnit.HOURS);
			scheduledExecutor.scheduleWithFixedDelay(
					new PackageProductLineTask(), 0, 1, TimeUnit.HOURS);
		}
	}
	
	/**
	 * 产品线组装 
	 * @author haqiaolong
	 *
	 */
	private class PackageProductLineTask implements Runnable{

		@Override
		public void run() {
			try {
				List<ProductLineTree> nodes = productLineBiz.selectByLevel(1);
				if(CollectionUtils.isNotEmpty(nodes)){
					for(ProductLineTree productLineTree : nodes){
						List<ProductLineTree> elements = productLineBiz.selectByPId(productLineTree.getId());
						if(CollectionUtils.isNotEmpty(elements)){
							productLineTree.getNodes().addAll(elements);
							processProductLine(productLineTree,elements,false);
						}
					}
				}
				RedisUtil.getStringRedisTemplate().opsForValue().set(GlobalConstant.GDOCKER_PRODUCT_TREE, JSON.toJSONString(nodes));
				logger.info("update product line is complete!");
			} catch (DaoException e) {
				logger.equals("process product line task is error !" + e);
			}
		}
		
		private void processProductLine(ProductLineTree parentLineTree,List<ProductLineTree> nodes,boolean isChild) throws DaoException{
			for(ProductLineTree productLineTree : nodes){
				if(productLineTree.getId()==8814) {
					continue;
				}
				if(productLineTree != null){
					if(isChild){
						List<ProductLineTree> children = productLineBiz.selectByPId(productLineTree.getId());
						if(children.isEmpty()){
							continue;
						}
						boolean hasChildren = false;
						for(ProductLineTree c : children) {
							List<ProductLineTree> secondLevelChildren = productLineBiz.selectByPId(c.getId());
							if(!secondLevelChildren.isEmpty()) {
								hasChildren = true;
							}
						}
						if(hasChildren) {
							parentLineTree.getNodes().add(productLineTree);
						}else {
							continue;
						}
					}
					List<ProductLineTree> childs = productLineBiz.selectByPId(productLineTree.getId());
					if(CollectionUtils.isNotEmpty(childs)){
						processProductLine(productLineTree,childs,true);
					}
				}
			}
		}
	}

	/**
	 * 更新产品树
	 * @author haqiaolong
	 *
	 */
	private class UpdateProductLineTask implements Runnable {

		@Override
		public void run() {
			logger.info("start sync cmdb data!");
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("nodegroup_id_list", Arrays.asList(9368));
			String result = HttpClientUtil.doPost(cmdbApi, params);
			if (StringUtils.isEmpty(result)) {
				logger.error("cmdb productline api is error! please check!");
			}
			try {
				JsonNode r = mapper.readValue(result, JsonNode.class);
				JsonNode data = r.path("data");
				List<JsonNode> jsonNodes = data.findParents("nodegroup_info");
				for (int i = 0; i < jsonNodes.size(); i++) {
					getChild(jsonNodes.get(i));
				}
			} catch (IOException | DaoException e) {
				logger.error("cmdb productline parse error!" + e);
				return;
			}
			logger.info("sync cmdb data end!");
		}
	}
	
	private void insertOrUpdateTree(JsonNode node) throws DaoException {
		if(node.has("id")){
			int id = node.path("id").asInt();
			int idCount = productLineBiz.getCountById(id);
			ProductLine productLine;
			
			if(idCount == 1) {
				productLine = productLineBiz.selectById(id);
				productLine.setpId(node.path("father_id").asInt());
				productLine.setName(node.path("app_name").asText());
				productLine.setDescription(node.path("description").asText());
				productLine.setLevel(node.path("level").asInt());
				productLine.setEnv(node.path("env").asText());
				productLineBiz.updateProductLine(productLine);
			} else if (idCount == 0){
				productLine = new ProductLine();
				productLine.setId(id);
				productLine.setpId(node.path("father_id").asInt());
				productLine.setName(node.path("app_name").asText());
				productLine.setDescription(node.path("description").asText());
				productLine.setLevel(node.path("level").asInt());
				productLine.setEnv(node.path("env").toString());
				productLineBiz.addProductLine(productLine);
			}
		}
	}

	private void getChild(JsonNode node) throws DaoException{
		if (node.has("nodegroup_info")) {
			JsonNode ndetail = node.path("nodegroup_info");
			if(ndetail.isArray()){
				for (JsonNode j : ndetail) {
					getChild(j);
				}
			}else{
				getChild(ndetail);
			}
		}
		if(node.has("children_info")){
			JsonNode childr = node.path("children_info");
			if(childr.isArray()){
				for(JsonNode j : childr){
					getChild(j);
				}
			}else{
				getChild(childr);
			}
		}
		insertOrUpdateTree(node);
	}
}
